# -*- coding: utf-8-*-
import time
import uuid
import cProfile
import pstats
import io
import re
import os
from snowboy import snowboydecoder
from robot import ASR, TTS, AI, Player, constants, utils, features
import random


class Conversation(object):

    def __init__(self, profiling=False):

        self.reInit()

        self.isRecording = False
        self.profiling = profiling
        self.onSay = None
        self.hasPardon = False
        self.dialog = False

        self.list = ["电阻", "单片机", "蓝牙模块", "下载器", "电容"]

    def interrupt(self):
        if self.player is not None and self.player.is_playing():
            self.player.stop()
            self.player = None

    def reInit(self):
        """ 重新初始化 """
        try:

            appid = '9670645'
            api_key = 'qg4haN8b2bGvFtCbBGqhrmZy'
            secret_key = '585d4eccb50d306c401d7df138bb02e7'

            self.asr = ASR.BaiduASR(appid, api_key, secret_key)
            self.ai = AI.TulingRobot("ed5b58ddac944c46ba84e897dcb9b00a")
            self.tts = TTS.BaiduTTS(appid, api_key, secret_key)

            self.player = None

        except Exception as e:
            print("对话初始化失败：{}".format(e))

    def doResponse(self, query, UUID='', onSay=None):

        self.interrupt()

        if onSay:
            self.onSay = onSay

        if query.strip() == '':
            self.pardon()
            return

        if any(word in query for word in ['开启', '激活', '开始', '进入', '打开']):
            self.dialog = True
            self.say('进入极客模式', cache=True,
                     onCompleted=lambda: self.activeListen(silent=True))
            return

        elif any(word in query for word in ['关闭', '结束', '退出', '关掉']):
            self.dialog = False
            self.say('退出极客模式', cache=True)
            return

        # 命中关键词，较傻的关键词匹配
        for i in self.list:
            if i in query:
                msg = "正在取出"+i
                if self.dialog == True:
                    self.say(msg, True,
                             onCompleted=lambda: self.activeListen(silent=True))
                else:
                    self.say(msg, True)
                features.match(i)
                return

        # 没命中技能，使用机器人回复
        # else:
        #     msg = self.ai.chat(query)
        #     self.say(msg, True)

        # 没命中技能，回复固定内容
        else:
            """
            不知道怎么回答的情况下的答复
            :returns: 表示不知道的答复
            """
            results = [
                "抱歉，我不会这个呢",
                "我不会这个呢",
                "我还不会这个呢",
                "我还没学会这个呢",
                "对不起，你说的这个，我还不会"
            ]
            msg = random.choice(results)
            if self.dialog == True:
                self.say(msg, True,
                         onCompleted=lambda: self.activeListen(silent=True))
            else:
                self.say(msg, True)

    def doParse(self, query, **args):
        return self.nlu.parse(query, **args)

    def converse(self, fp, callback=None):
        """ 核心对话逻辑 """
        Player.play(constants.getData('beep_lo.wav'))
        print('结束录音')
        self.isRecording = False

        self.doConverse(fp, callback)

    def doConverse(self, fp, callback=None, onSay=None):
        try:
            self.interrupt()
            query = self.asr.transcribe(fp)
            utils.check_and_delete(fp)
            self.doResponse(query, callback, onSay)
        except Exception as e:
            print(e)
            utils.clean()

    def _onCompleted(self, msg):
        if False and \
           (
               msg.endswith('?') or
               msg.endswith(u'？') or
               u'告诉我' in msg or u'请回答' in msg
           ):
            query = self.activeListen()
            self.doResponse(query)

    def pardon(self):
        if not self.hasPardon:
            self.say("抱歉，刚刚没听清，能再说一遍吗？",
                     onCompleted=lambda: self.doResponse(self.activeListen()))
            self.hasPardon = True
        else:
            self.say("没听清呢")
            self.hasPardon = False

    def say(self, msg, cache=False, plugin='', onCompleted=None, wait=False):
        """ 
        说一句话
        :param msg: 内容
        :param cache: 是否缓存这句话的音频
        :param plugin: 来自哪个插件的消息（将带上插件的说明）
        :param onCompleted: 完成的回调
        :param wait: 是否要等待说完（为True将阻塞主线程直至说完这句话）
        """
        voice = ''
        cache_path = ''
        if utils.getCache(msg):
            print("命中缓存，播放缓存语音")
            voice = utils.getCache(msg)
            cache_path = utils.getCache(msg)
        else:
            try:
                voice = self.tts.get_speech(msg)
                cache_path = utils.saveCache(voice, msg)
            except Exception as e:
                print('保存缓存失败：{}'.format(e))
        if onCompleted is None:
            def onCompleted(): return self._onCompleted(msg)
        self.player = Player.SoxPlayer()
        self.player.play(voice, not cache, onCompleted, wait)
        if not cache:
            utils.check_and_delete(cache_path, 60)  # 60秒后将自动清理不缓存的音频
        utils.lruCache()  # 清理缓存

    def activeListen(self, silent=False):
        """ 主动问一个问题(适用于多轮对话) """
        print('activeListen')
        try:
            print(silent)
            if not silent:
                Player.play(constants.getData('beep_hi.wav'))

            listener = snowboydecoder.ActiveListener(
                [constants.getHotwordModel("小白.pmdl")])

            voice = listener.listen(
                silent_count_threshold=100,
                recording_timeout=5 * 4
            )
            if not silent:
                Player.play(constants.getData('beep_lo.wav'))
            if voice:
                query = self.asr.transcribe(voice)
                utils.check_and_delete(voice)
                # 为了进行对话，需要接着回调函数
                self.doResponse(query)
                # return query
            return ''
        except Exception as e:
            print('出现异常')
            print(e)
            return ''

    def play(self, src, delete=False, onCompleted=None, volume=1):
        """ 播放一个音频 """
        if self.player:
            self.interrupt()
        self.player = Player.SoxPlayer()
        self.player.play(src, delete=delete, onCompleted=onCompleted)
